/*
 * @Author: sichuntian sichuntian@smartmappingtek.com
 * @Date: 2024-02-07 10:10:22
 * @LastEditors: sichuntian sichuntian@smartmappingtek.com
 * @LastEditTime: 2024-05-16 15:21:25
 * @Description:
 *
 */
import * as mars3d from "mars3d";
import "mars3d-space";
const Cesium = mars3d.Cesium;
import * as turf from "@turf/turf";

import Measure from "./modules/measure";

class Map {
  constructor(container, options, callbackOptions) {
    this.marsMap = new mars3d.Map(container, options);
    this.graphicLayer = new mars3d.layer.GraphicLayer();
    this.marsMap.addLayer(this.graphicLayer);

    this.marsMap.scene.globe.depthTestAgainstTerrain = true; // 开启深度检测，否则矢量图形会飘

    // 浏览器奔溃以后刷新页面
    this.marsMap.on(mars3d.EventType.renderError, function (event) {
      window.location.reload();
    });

    this.marsMap.on(mars3d.EventType.click, (event) => {
      const point = mars3d.LngLatPoint.fromCartesian(event.cartesian);
      let position = [point.lng, point.lat, point.alt];
      callbackOptions.getClickPosition(position);
    });

    // 实例化测量模块
    const measureInstance = new Measure(this.marsMap);

    this.bindLayerContextMenu();
  }

  // 加载3dtiles模型
  load3DtilesModel(url, sceneId) {
    const tilesetLayer = this.marsMap.getLayerById(url);
    if (tilesetLayer) {
      tilesetLayer.flyTo({
        duration: 1,
      });
      return false;
    }
    const tiles3dLayer = new mars3d.layer.TilesetLayer({
      id: url,
      url: url,
      maximumScreenSpaceError: 16, // 【重要】数值加大，能让最终成像变模糊
      cacheBytes: 1073741824, // 1024MB = 1024*1024*1024 【重要】额定显存大小(以字节为单位)，允许在这个值上下波动。
      maximumCacheOverflowBytes: 2147483648, // 2048MB = 2048*1024*1024 【重要】最大显存大小(以字节为单位)。
      maximumMemoryUsage: 512, //【cesium 1.107+弃用】内存建议显存大小的50%左右，内存分配变小有利于倾斜摄影数据回收，提升性能体验
      skipLevelOfDetail: true, //是Cesium在1.5x 引入的一个优化参数，这个参数在金字塔数据加载中，可以跳过一些级别，这样整体的效率会高一些，数据占用也会小一些。但是带来的异常是：1） 加载过程中闪烁，看起来像是透过去了，数据载入完成后正常。2，有些异常的面片，这个还是因为两级LOD之间数据差异较大，导致的。当这个参数设置false，两级之间的变化更平滑，不会跳跃穿透，但是清晰的数据需要更长，而且还有个致命问题，一旦某一个tile数据无法请求到或者失败，导致一直不清晰。所以我们建议：对于网络条件好，并且数据总量较小的情况下，可以设置false，提升数据显示质量。
      loadSiblings: true, // 如果为true则不会在已加载完模型后，自动从中心开始超清化模型
      cullRequestsWhileMoving: true,
      cullRequestsWhileMovingMultiplier: 10, //【重要】 值越小能够更快的剔除
      preferLeaves: true, //【重要】这个参数默认是false，同等条件下，叶子节点会优先加载。但是Cesium的tile加载优先级有很多考虑条件，这个只是其中之一，如果skipLevelOfDetail=false，这个参数几乎无意义。所以要配合skipLevelOfDetail=true来使用，此时设置preferLeaves=true。这样我们就能最快的看见符合当前视觉精度的块，对于提升大数据以及网络环境不好的前提下有一点点改善意义。
      progressiveResolutionHeightFraction: 0.5, //【重要】 数值偏于0能够让初始加载变得模糊
      dynamicScreenSpaceError: true, // true时会在真正的全屏加载完之后才清晰化模型
      preloadWhenHidden: true, //tileset.show是false时，也去预加载数据
      // position: { alt_offset: Number(offsetHeight) },
      flyTo: true,
    });
    const tile = this.marsMap.addLayer(tiles3dLayer);
    tile.then((res) => {
      console.log("模型已经加载");
    });
  }
  // 加载3dtiles模型
  load3Dtiles(id, url, offsetHeight = 0) {
    const tilesetLayer = this.marsMap.getLayerById(url);
    if (tilesetLayer) this.marsMap.removeLayer(tilesetLayer);
    const tiles3dLayer = new mars3d.layer.TilesetLayer({
      id: id,
      url: url,
      position: { alt_offset: Number(offsetHeight) },
      flyTo: true,
    });
    this.marsMap.addLayer(tiles3dLayer);
  }
  // 更新3dtiles模型
  update3Dtiles(id, params) {
    const tilesetLayer = this.marsMap.getLayerById(id);
    if (!tilesetLayer) return false;
    tilesetLayer.setOptions(params);
  }
  // 加载gltf模型
  loadGltf(id, url, pos, hpr, isFill, offsetHeight = 0) {
    const gltfGraphic = this.graphicLayer.getGraphicById(id);
    if (gltfGraphic) this.removeGraphicByIds([id]);
    const graphic = new mars3d.graphic.ModelEntity({
      id: id,
      position: pos,
      style: {
        url: url,
        heading: hpr.heading,
        pitch: hpr.pitch,
        roll: hpr.roll,
        scale: 1,
        minimumPixelSize: 1,
        clampToGround: false,
        HeightReference: Cesium.HeightReference.NONE,
        addHeight: offsetHeight,
        fill: isFill,
        color: "#383838",
      },
      flyTo: true,
    });
    this.graphicLayer.addGraphic(graphic);
    graphic.on(mars3d.EventType.dblClick, (e) => {
      // console.log("点击贴地gltf")
    });
  }
  // 更新gltf模型
  updateGraphicbyId(id, params) {
    const gltfGraphic = this.graphicLayer.getGraphicById(id);
    if (!gltfGraphic) return false;
    gltfGraphic.setOptions(params);
  }
  // 移除矢量数据
  removeGraphicByIds(ids) {
    ids.forEach((id) => {
      const graphic = this.graphicLayer.getGraphicById(id);
      if (graphic) this.graphicLayer.removeGraphic(graphic);
    });
  }
  // 加载矢量数据
  loadGeojson(url) {
    const graphicLayer = new mars3d.layer.GeoJsonLayer({
      id: "geojsonLine",
      name: "高速公路",
      url: url,
      symbol: {
        type: "polyline",
        styleOptions: {
          visibleDepth: false,
          width: 2,
          materialType: mars3d.MaterialType.LineFlow,
          materialOptions: {
            color: "#00ffff",
            speed: 10,
            repeat_x: 10,
          },
          clampToGround: true,
        },
      },
      clustering: {
        clampToGround: true,
      },
      flyTo: false,
    });
    this.marsMap.addLayer(graphicLayer);
  }
  // 绘制立体面
  drawSolidArea() {
    this.graphicLayer.startDraw({
      type: "polygon",
      style: {
        color: "#00ff00",
        opacity: 0.3,
        diffHeight: 120,
      },
    });
  }
  bindLayerContextMenu() {
    this.graphicLayer.bindContextMenu([
      {
        text: "开始编辑对象",
        icon: "fa fa-edit",
        show: function (e) {
          const graphic = e.graphic;
          if (!graphic || !graphic.hasEdit) {
            return false;
          }
          return !graphic.isEditing;
        },
        callback: (e) => {
          const graphic = e.graphic;
          if (!graphic) {
            return false;
          }
          if (graphic) {
            this.graphicLayer.startEditing(graphic);
          }
        },
      },
      {
        text: "停止编辑对象",
        icon: "fa fa-edit",
        show: function (e) {
          const graphic = e.graphic;
          if (!graphic || !graphic.hasEdit) {
            return false;
          }
          return graphic.isEditing;
        },
        callback: (e) => {
          const graphic = e.graphic;
          if (!graphic) {
            return false;
          }
          if (graphic) {
            graphic.stopEditing();
          }
        },
      },
      {
        text: "删除对象",
        icon: "fa fa-trash-o",
        show: (event) => {
          const graphic = event.graphic;
          if (!graphic || graphic.isDestroy) {
            return false;
          } else {
            return true;
          }
        },
        callback: (e) => {
          const graphic = e.graphic;
          if (!graphic) {
            return;
          }
          const parent = graphic.parent; // 右击是编辑点时
          this.graphicLayer.removeGraphic(graphic);
          if (parent) {
            this.graphicLayer.removeGraphic(parent);
          }
        },
      },
    ]);
  }
  addModel(id, url, pos, scale) {
    const gltfGraphic = this.graphicLayer.getGraphicById(id);
    if (gltfGraphic) this.removeGraphicByIds([id]);
    const graphic = new mars3d.graphic.ModelEntity({
      id: id,
      position: pos,
      style: {
        url: url,
        scale: scale,
        minimumPixelSize: 1,
        clampToGround: url == "models/air.glb" ? false : true,
        heightReference:
          url == "models/air.glb"
            ? Cesium.HeightReference.RELATIVE_TO_GROUND
            : Cesium.HeightReference.NONE,
      },
    });
    this.graphicLayer.addGraphic(graphic);
  }
  addWall() {
    this.graphicLayer.startDraw({
      type: "wallP",
      style: {
        color: "#55ff33",
        opacity: 0.8,
        diffHeight: 300,
        closure: true,
      },
    });
  }
}
export default Map;
